/*

* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     Smart-Shop开源商城系统/ Java商城-首选电商平台系统 请务必保留此注释头信息
* |     开源地址: https://gitee.com/ningbo-qishan/gruul-mall
* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     可正常分享和学习源码,未经授权 不可商用！
* |     商业版中台购买/开源版商业授权 联系技术客服
* |     官网:  https://www.73app.cn/
* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     Copyright (c) 2016-2999 宁波启山智软科技有限公司
* |     版权所有 ,侵权必究！
* ------------------------------------------------------------------------

*/
package com.medusa.gruul.finance.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.medusa.gruul.common.core.constant.CommonConstants;
import com.medusa.gruul.common.core.util.PageUtils;
import com.medusa.gruul.datasets.api.feign.RemoteDataSetsService;
import com.medusa.gruul.datasets.api.model.CallerDto;
import com.medusa.gruul.finance.api.entity.FinanceTradeDetail;
import com.medusa.gruul.finance.api.enums.FlowTypeEnum;
import com.medusa.gruul.finance.api.enums.TradeTypeEnum;
import com.medusa.gruul.finance.mapper.FinanceTradeDetailMapper;
import com.medusa.gruul.finance.model.SearchTradeDetailDto;
import com.medusa.gruul.finance.model.ShopOverviewVo;
import com.medusa.gruul.finance.model.TradeOverviewVo;
import com.medusa.gruul.finance.service.IFinanceTradeDetailService;
import com.medusa.gruul.finance.util.GenSerialNumberUtil;
import com.medusa.gruul.order.api.feign.RemoteOrderService;
import com.medusa.gruul.order.api.model.OrderVo;
import com.medusa.gruul.order.api.model.TradeLineVo;
import com.medusa.gruul.order.api.model.TradeVo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 资金交易明细表 服务实现类
 * </p>
 *
 * @author alan
 * @since 2020 -02-22
 */
@Service
public class FinanceTradeDetailServiceImpl extends ServiceImpl<FinanceTradeDetailMapper, FinanceTradeDetail> implements IFinanceTradeDetailService {

    @Resource
    private RemoteOrderService orderService;
    @Resource
    private RemoteDataSetsService dataSetsService;

    @Override
    public PageUtils getTradeDetailPage(SearchTradeDetailDto dto) {
        IPage page = null;
        setDefaultTime(dto);
        page = baseMapper.selectPage(new Page(dto.getCurrent(), dto.getSize()),
                new LambdaQueryWrapper<FinanceTradeDetail>()
                        .eq(dto.getFlowType().equals(0), FinanceTradeDetail::getCapitalFlows, FlowTypeEnum.IN)
                        .eq(dto.getFlowType().equals(1), FinanceTradeDetail::getCapitalFlows, FlowTypeEnum.OUT)
                        .eq(ObjectUtil.isNotNull(dto.getType()), FinanceTradeDetail::getType, dto.getType())
                        .between(FinanceTradeDetail::getCreateTime, dto.getStartTime(), dto.getEndTime())
                        .orderByDesc(FinanceTradeDetail::getCreateTime)
        );
        return new PageUtils(page);
    }

    @Override
    public TradeOverviewVo getTradeOverview(SearchTradeDetailDto dto) {
        setDefaultTime(dto);
        List<FinanceTradeDetail> inList = baseMapper.selectList(new LambdaQueryWrapper<FinanceTradeDetail>()
                .select(FinanceTradeDetail::getAmount)
                .eq(FinanceTradeDetail::getCapitalFlows, FlowTypeEnum.IN)
                .between(FinanceTradeDetail::getCreateTime, dto.getStartTime(), dto.getEndTime())
        );
        List<FinanceTradeDetail> outList = baseMapper.selectList(new LambdaQueryWrapper<FinanceTradeDetail>()
                .select(FinanceTradeDetail::getAmount)
                .eq(FinanceTradeDetail::getCapitalFlows, FlowTypeEnum.OUT)
                .between(FinanceTradeDetail::getCreateTime, dto.getStartTime(), dto.getEndTime())
        );
        TradeOverviewVo tradeOverviewVo = new TradeOverviewVo();
        tradeOverviewVo.setIncomeNumber(inList.size());
        tradeOverviewVo.setIncomeAmount(inList.stream().map(FinanceTradeDetail::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        tradeOverviewVo.setExpensesNumber(outList.size());
        tradeOverviewVo.setExpensesAmount(outList.stream().map(FinanceTradeDetail::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        return tradeOverviewVo;
    }

    private void setDefaultTime(SearchTradeDetailDto dto) {
        if (StrUtil.isBlank(dto.getStartTime())) {
            dto.setStartTime(DateUtil.beginOfMonth(new Date()).toString());
        } else {
            dto.setStartTime(dto.getStartTime() + " 00:00:00");
        }
        if (StrUtil.isBlank(dto.getEndTime())) {
            dto.setEndTime(DateUtil.endOfMonth(new Date()).toString());
        } else {
            dto.setEndTime(dto.getEndTime() + " 23:59:59");
        }
    }

    @Override
    public void addTrade(OrderVo orderVo) {
        FinanceTradeDetail detail = new FinanceTradeDetail();
        detail.setTradeNo(orderVo.getTransactionId());
        detail.setUserId(orderVo.getUserId());
        detail.setUserName(orderVo.getUserName());
        detail.setUserAvatarUrl(orderVo.getUserAvatarUrl());
        detail.setType(TradeTypeEnum.TRADE);
        detail.setAmount(orderVo.getPayAmount());
        detail.setSourceId(orderVo.getId());
        detail.setCapitalFlows(FlowTypeEnum.IN);
        detail.setSn(GenSerialNumberUtil.initGenSerialNumber(GenSerialNumberUtil.BROKERAGE, orderVo.getShopId()).nextId());
        baseMapper.insert(detail);
    }

    @Override
    public boolean addReturn(OrderVo orderVo) {
        FinanceTradeDetail detail = new FinanceTradeDetail();
        detail.setTradeNo(orderVo.getRefundTransactionId());
        detail.setUserId(orderVo.getUserId());
        detail.setUserName(orderVo.getUserName());
        detail.setUserAvatarUrl(orderVo.getUserAvatarUrl());
        detail.setType(TradeTypeEnum.RETURN);
        detail.setAmount(orderVo.getRefundAmount());
        detail.setSourceId(orderVo.getId());
        detail.setCapitalFlows(FlowTypeEnum.OUT);
        detail.setSn(GenSerialNumberUtil.initGenSerialNumber(GenSerialNumberUtil.BROKERAGE, orderVo.getShopId()).nextId());
        baseMapper.insert(detail);
        return true;
    }


    @Override
    public TradeVo getTradeVoByTime(String startDate, String endDate) {
        return baseMapper.getTradeVoByTime(startDate.concat(" 00:00:00"), endDate.concat(" 23:59:59"));
    }

    @Override
    public List<TradeLineVo> getTradeVoGroupByDate(String startDate, String endDate) {
        return baseMapper.getTradeVoGroupByDate(startDate.concat(" 00:00:00"), endDate.concat(" 23:59:59"));
    }

    @Override
    public ShopOverviewVo getOverview(String startTime, String endTime) {
        ShopOverviewVo vo = new ShopOverviewVo();
        DateTime startDate;
        DateTime endDate;
        if (StrUtil.isNotBlank(startTime) && StrUtil.isNotBlank(endTime)) {
            startDate = DateUtil.parse(startTime);
            endDate = DateUtil.endOfDay(DateUtil.parse(endTime));
            TradeVo tradeVo = getTradeVoByTime(startTime, endTime);
            CallerDto callerDto = dataSetsService.callerInfo(Integer.parseInt(DateUtil.beginOfDay(startDate).toString(
                    "yyyyMMdd")),
                    Integer.parseInt(DateUtil.endOfDay(endDate).toString("yyyyMMdd")));
            tradeVo.setViews(callerDto.getPv());
            vo.setTrade(tradeVo);
        } else {
            TradeVo tradeVo = getTradeVoByTime(DateUtil.today(), DateUtil.today());
            Integer start = Integer.parseInt(DateUtil.date().toString(
                    "yyyyMMdd"));
            CallerDto callerDto = dataSetsService.callerInfo(start, null);

            TradeVo yesterdayTradeVo = getTradeVoByTime(DateUtil.yesterday().toDateStr(),
                    DateUtil.yesterday().toDateStr());
            if (ObjectUtil.isNotNull(callerDto)) {
                tradeVo.setViews(callerDto.getPv());
                yesterdayTradeVo.setViews(callerDto.getYesterdayPv());
            }
            vo.setTrade(tradeVo);
            vo.setYesterdayTrade(yesterdayTradeVo);
            startDate = DateUtil.offsetDay(DateUtil.parse(DateUtil.today()), -6);
            endDate = DateUtil.parse(DateUtil.today());
        }
        long betweenDay = DateUtil.betweenDay(startDate, endDate, true) + 1;
        List<TradeLineVo> tradeVoList = getTradeVoGroupByDate(startDate.toDateStr(), endDate.toDateStr());
        Map<String, TradeLineVo> tradeVoMap = tradeVoList.stream()
                .collect(Collectors.toMap(TradeLineVo::getDate, v -> v));
        for (int i = 0; i < betweenDay; i++) {
            String dateStr = DateUtil.offsetDay(startDate, i).toDateStr();
            if (ObjectUtil.isNull(tradeVoMap.get(dateStr))) {
                TradeLineVo tradeLineVo = new TradeLineVo();
                tradeLineVo.setDate(dateStr);
                tradeVoList.add(tradeLineVo);
            }
        }
        tradeVoList.sort(Comparator.comparing(TradeLineVo::getDate));
        vo.setTradeLineVos(tradeVoList);
        vo.setUpdateTime(DateUtil.now());
        return vo;
    }

    @Override
    public void addRebateDetail(OrderVo vo) {
        BigDecimal rebateAmount = vo.getRebateAmount();
        if (rebateAmount == null || rebateAmount.compareTo(BigDecimal.ZERO) <= CommonConstants.NUMBER_ZERO) {
            log.warn("消费返利队列回 ===》 订单id：".concat(vo.getId().toString()).concat(", 消费返利金额为0，不进行处理"));
            return;
        }
        FinanceTradeDetail detail = new FinanceTradeDetail();
        detail.setTenantId(vo.getTenantId());
        detail.setShopId(vo.getShopId());
        detail.setTradeNo(vo.getTransactionId());
        detail.setUserId(vo.getUserId());
        detail.setUserName(vo.getUserName());
        detail.setUserAvatarUrl(vo.getUserAvatarUrl());
        detail.setType(TradeTypeEnum.REBATE);
        detail.setAmount(rebateAmount);
        detail.setSourceId(vo.getId());
        detail.setCapitalFlows(FlowTypeEnum.OUT);
        detail.setSn(GenSerialNumberUtil.initGenSerialNumber(GenSerialNumberUtil.BROKERAGE, vo.getShopId()).nextId());
        super.save(detail);

    }

}
